﻿using IotClientApp.Server.Devices;
using IotClientApp.Server.Entity;
using IotClientApp.Shared;
using IotClientApp.Shared.Enums;
using IotModel;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using PluginInterface;
using System;

namespace IotClientApp.Server.Services
{
    public class DeviceService : IDeviceService
    {
        private readonly DeviceClientHost _deviceClientHost;
        private readonly IotDBContext _iotDBContext;
        private readonly ILogger<IParamService> _logger;
        public DeviceService(IotDBContext iotDBContext, ILogger<IParamService> logger, DeviceClientHost deviceClientHost)
        {
            _iotDBContext = iotDBContext;
            _logger = logger;
            _deviceClientHost = deviceClientHost;
        }
        /// <summary>
        /// 获取所有设备
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PageResponse<DeviceInfoModel>> GetDeviceInfos(GetDeviceInfoModel input)
        {
            var result = new PageResponse<DeviceInfoModel> { Data = new List<DeviceInfoModel> { } };
            try
            {
                var query = _iotDBContext.Device.AsQueryable();
                if (input.IsActive != null)
                {
                    query = query.Where(t => t.IsActive);
                }
                if (!string.IsNullOrEmpty(input.KeyWord))
                {
                    query = query.Where(t => input.KeyWord.Contains(t.Name));
                }
                query = query.OrderBy(t => t.Name);
                result.PageCount = (int)Math.Floor(query.Count() * 1.0 / input.PageSize);
                if (input.PageIndex > 0 && input.PageSize > 0)
                {
                    query = query.Skip((input.PageIndex - 1) * input.PageSize).Take(input.PageSize);
                }
                var deviceEntitys = await query.AsNoTracking().ToListAsync();
                foreach (var deviceEntity in deviceEntitys)
                {
                    result.Data.Add(new DeviceInfoModel
                    {
                        Id = deviceEntity.Id,
                        Name = deviceEntity.Name,
                        Desc = deviceEntity.Desc,
                        IsActive = deviceEntity.IsActive,
                        CreateTime = deviceEntity.CreateTime
                    });
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"GetDeviceInfos{ex.Message}");
            }
            return result;
        }
        /// <summary>
        /// 设备编辑
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiResult<DeviceInfoModel>> SaveDeviceInfo(DeviceInfoModel input)
        {
            var result = new ApiResult<DeviceInfoModel> { };
            try
            {
                if (string.IsNullOrWhiteSpace(input.Name))
                {
                    result.Code = ResultCode.BadRequest;
                    return result;
                }
                var isExit = _iotDBContext.Device.Any(t => t.Id != input.Id && t.Name == input.Name);
                if (isExit)
                {
                    result.Code = ResultCode.Exist;
                    return result;
                }
                IotClientApp.Server.Entity.Device? deviceInfo;
                if (!string.IsNullOrEmpty(input.Id))
                {
                    deviceInfo = _iotDBContext.Device.FirstOrDefault(t => t.Id == input.Id);
                    if (deviceInfo == null)
                    {
                        result.Code = ResultCode.NotExist;
                        return result;
                    }
                    _iotDBContext.Attach(deviceInfo);
                    _iotDBContext.Entry(deviceInfo).Property(p => p.Name).IsModified = true;
                    _iotDBContext.Entry(deviceInfo).Property(p => p.Desc).IsModified = true;
                }
                else
                {
                    deviceInfo = new Entity.Device
                    {
                        Id = Guid.NewGuid().ToString("N"),
                        CreateTime = DateTime.Now
                    };
                    _iotDBContext.Device.Add(deviceInfo);
                }
                deviceInfo.Name = input.Name;
                deviceInfo.Desc = input.Desc;
                await _iotDBContext.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError($"GetDeviceInfos{ex.Message}");
            }
            return result;
        }

        /// <summary>
        /// 开始设备采集任务
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        public async Task<string> StartDevice(DeviceModel device)
        {
            await _deviceClientHost.StartDevice(device);
            return string.Empty;
        }
        /// <summary>
        /// 启用/禁用设备采集数据
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="isActive"></param>
        /// <returns></returns>
        public async Task<ApiResult<string>> EnableDevice(string deviceId, bool isActive)
        {
            var result = new ApiResult<string> { };
            var device = _iotDBContext.Device.FirstOrDefault(t => t.Id == deviceId);
            if (device == null)
            {
                result.Code = ResultCode.NotExist;
                return result;
            }
            _iotDBContext.Attach(device);
            _iotDBContext.Entry(device).Property(p => p.IsActive).IsModified = true;
            device.IsActive = isActive;
            await _iotDBContext.SaveChangesAsync();
            if (isActive)
            {
                var deivces = await GetDevices(new List<string> { deviceId });
                if (deivces != null && deivces.Count() > 0)
                {
                    await StartDevice(deivces.First());
                }
            }
            else
            {
                _deviceClientHost.StopDevice(deviceId);
            }
            return result;
        }
        public async Task<List<DeviceModel>> GetDevices()
        {
            return await GetDevices(null);
        }
        /// <summary>
        /// 获取所有设备
        /// </summary>
        /// <param name="queryDeviceIds"></param>
        /// <returns></returns>
        public async Task<List<DeviceModel>> GetDevices(List<string>? queryDeviceIds)
        {
            var devices = new List<DeviceModel> { };
            var query = _iotDBContext.Device.Where(t => t.IsActive);
            if (queryDeviceIds != null && queryDeviceIds.Count() > 0)
            {
                query = query.Where(t => queryDeviceIds.Contains(t.Id));
            }
            var deviceEntitys = await query.AsNoTracking().ToListAsync();
            var deviceIds = deviceEntitys.Select(t => t.Id).ToList();
            var deviceConfigEntitys = await _iotDBContext.DeviceConfig.Where(t => deviceIds.Contains(t.DeviceId)).AsNoTracking().ToListAsync();
            var pointEntitys = await _iotDBContext.Point.Where(t => deviceIds.Contains(t.DeviceId)).AsNoTracking().ToListAsync();
            foreach (var deviceEntity in deviceEntitys)
            {
                var device = new DeviceModel { DeviceId = deviceEntity.Id, DeviceName = deviceEntity.Name, AutoStart = true, DeviceConfigs = new List<DeviceConfigModel> { }, DeviceVariables = new List<DeviceVariableModel> { } };
                var _deviceConfigEntitys = deviceConfigEntitys.Where(t => t.DeviceId == deviceEntity.Id).OrderBy(t => t.Name).ToList();
                foreach (var _deviceConfigEntity in _deviceConfigEntitys)
                {
                    device.DeviceConfigs.Add(new DeviceConfigModel
                    {
                        Description = _deviceConfigEntity.Desc,
                        DeviceConfigName = _deviceConfigEntity.Name,
                        Value = _deviceConfigEntity.Value,
                        EnumInfo = _deviceConfigEntity.EnumInfo
                    });
                    if (!string.IsNullOrEmpty(deviceEntity.MqttServer))
                    {
                        device.MqttServer = JsonConvert.DeserializeObject<MqttServerModel>(deviceEntity.MqttServer);
                    }
                }
                var _pointEntitys = pointEntitys.Where(t => t.DeviceId == deviceEntity.Id).OrderBy(t => t.Address).ToList();
                foreach (var pointEntity in _pointEntitys)
                {
                    device.DeviceVariables.Add(new DeviceVariableModel
                    {
                        Name = pointEntity.Name,
                        DataType = (DataTypeEnum)Enum.Parse(typeof(DataTypeEnum), pointEntity.DataType.ToString()),
                        EndianType = (EndianEnum)Enum.Parse(typeof(EndianEnum), pointEntity.EndianType.GetValueOrDefault().ToString()),
                        Method = pointEntity.Method,
                        DeviceAddress = pointEntity.Address.ToString(),
                    });
                }
                devices.Add(device);
            }
            return devices;
        }
        /// <summary>
        /// 下控
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ApiResult<string>> ControlPoint(ControlPointModel input)
        {
            var result = new ApiResult<string> { Data = "Ok" };
            try
            {
                if (string.IsNullOrEmpty(input.DeviceId) || input.PointId <= 0 || string.IsNullOrWhiteSpace(input.Value))
                {
                    result.Code = ResultCode.BadRequest;
                    return result;
                }
                var point = _iotDBContext.Point.Where(t => t.DeviceId == input.DeviceId && t.Id == input.PointId).AsNoTracking().Select(t => new
                {
                    t.Address,
                    t.DataType,
                    t.EndianType
                }).FirstOrDefault();
                if (point == null)
                {
                    result.Code = ResultCode.Fail;
                    result.ErrorMsg = "参数未找到";
                    return result;
                }
                var dataType = (DataTypeEnum)Enum.Parse(typeof(DataTypeEnum), point.DataType.ToString());
                var endianType = (EndianEnum)Enum.Parse(typeof(EndianEnum), point.EndianType.ToString());
                var r = await _deviceClientHost.ControlPoint(input.DeviceId, point.Address, input.Value, dataType, endianType); ;
                result.Data = r;
            }
            catch (Exception ex)
            {
                result.Code = ResultCode.Fail;
                _logger.LogError($"ControlPoint{ex.Message}");
            }
            return result;
        }
    }
}